/**
 * Check if two given objects are the same (Note: this fn is not extensive in terms of depth equality)
 * @param {Object} a object a, to compare
 * @param {*} b object b, to compare
 * @returns {Boolean}
 */
function isIdenticalObject(a, b) {
	if (!a || !b) {
		return false;
	}

	const aProps = Object.getOwnPropertyNames(a);
	const bProps = Object.getOwnPropertyNames(b);

	if (aProps.length !== bProps.length) {
		return false;
	}

	const result = aProps.every(propName => {
		const aValue = a[propName];
		const bValue = b[propName];

		if (typeof aValue !== typeof bValue) {
			return false;
		}

		if (typeof aValue === `object` || typeof bValue === `object`) {
			return isIdenticalObject(aValue, bValue);
		}

		return aValue === bValue;
	});

	return result;
}

function identicalLinksSamePurposeAfter(results) {
	/**
	 * Skip, as no results to curate
	 */
	if (results.length < 2) {
		return results;
	}

	/**
	 * Filter results for which `result` is undefined & thus `data`, `relatedNodes` are undefined
	 */
	const incompleteResults = results.filter(
		({ result }) => result !== undefined
	);

	/**
	 * for each result
	 * - get other results with matching accessible name
	 * - check if same purpose is served
	 * - if not change `result` to `undefined`
	 * - construct a list of unique results with relatedNodes to return
	 */
	const uniqueResults = [];
	const nameMap = {};

	for (let index = 0; index < incompleteResults.length; index++) {
		const currentResult = incompleteResults[index];

		const { name, urlProps } = currentResult.data;
		/**
		 * This is to avoid duplications in the `nodeMap`
		 */
		if (nameMap[name]) {
			continue;
		}

		const sameNameResults = incompleteResults.filter(
			({ data }, resultNum) => data.name === name && resultNum !== index
		);
		const isSameUrl = sameNameResults.every(({ data }) =>
			isIdenticalObject(data.urlProps, urlProps)
		);

		/**
		 * when identical nodes exists but do not resolve to same url, flag result as `incomplete`
		 */
		if (sameNameResults.length && !isSameUrl) {
			currentResult.result = undefined;
		}

		/**
		 *  -> deduplicate results (for both `pass` or `incomplete`) and add `relatedNodes` if any
		 */
		currentResult.relatedNodes = [];
		currentResult.relatedNodes.push(
			...sameNameResults.map(node => node.relatedNodes[0])
		);

		/**
		 * Update `nodeMap` with `sameNameResults`
		 */
		nameMap[name] = sameNameResults;

		uniqueResults.push(currentResult);
	}

	return uniqueResults;
}

export default identicalLinksSamePurposeAfter;
